package com.basker.pisces.domain.validation.meta;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.Assert;

import com.basker.pisces.core.meta.annotation.DataField;
import com.basker.pisces.domain.constant.DomainConstants.ObjectErrorCode;
import com.basker.pisces.domain.property.meta.Property;
import com.basker.pisces.domain.validation.IValidationObjectError;
import com.basker.pisces.domain.value.IValueObject;
import com.basker.pisces.resource.StringResources;
import com.basker.pisces.service.exception.IObjectErrorsWrapper.ObjectError;

public class UniquePropertyValidation extends Validation {

    @DataField
    private List<String> uniquePropertyNames = new ArrayList<>();

    public UniquePropertyValidation() {

    }

    public UniquePropertyValidation(String name, String... uniquePropertyNames) {
        this.setName(name);

        if (!ArrayUtils.isEmpty(uniquePropertyNames)) {
            this.uniquePropertyNames.addAll(Arrays.asList(uniquePropertyNames));
        }
    }

    /**
     * 创建唯一属性并发冲突的错误
     *
     * @param dataObject
     * @param uniqueProperties
     * @return
     */
    public ObjectError createUniquePropertyConcurrentError(Object dataObject, List<Property<?>> uniqueProperties) {
        Assert.notNull(dataObject, "parameter 'dataObject' is required");
        Assert.notEmpty(uniqueProperties, "parameter 'uniqueProperties' is required");

        String propertyMessage = this.genPropertyMessage(dataObject, uniqueProperties);
        String errorMessage = StringResources.get("pisces-domain.UniquePropertyValidation.concurrent.violation",
                propertyMessage);

        UniquePropertyObjectError uniquePropertyObjectError = new UniquePropertyObjectError(
                ObjectErrorCode.UNIQUE_CONCURRENT_VIOLATION, dataObject, null, errorMessage);
        uniquePropertyObjectError.validation = this;

        return uniquePropertyObjectError;
    }

    /**
     * 创建唯一属性已存在的错误
     *
     * @param dataObject
     * @param uniqueProperties
     * @return
     */
    public ObjectError createUniquePropertyExistError(Object dataObject, List<Property<?>> uniqueProperties) {
        Assert.notNull(dataObject, "parameter 'dataObject' is required");
        Assert.notEmpty(uniqueProperties, "parameter 'uniqueProperties' is required");

        String propertyMessage = this.genPropertyMessage(dataObject, uniqueProperties);
        String errorMessage = StringResources.get("pisces-domain.UniquePropertyValidation.exist.violation",
                propertyMessage);

        UniquePropertyObjectError uniquePropertyObjectError = new UniquePropertyObjectError(
                ObjectErrorCode.UNIQUE_EXIST_VIOLATION, dataObject, null, errorMessage);
        uniquePropertyObjectError.validation = this;

        return uniquePropertyObjectError;
    }

    /**
     * 创建唯一属性在同一批次中存在多个的错误
     *
     * @param dataObject
     * @param uniqueProperties
     * @return
     */
    public ObjectError createUniquePropertyMultipleError(Object dataObject, List<Property<?>> uniqueProperties) {
        Assert.notNull(dataObject, "parameter 'dataObject' is required");
        Assert.notEmpty(uniqueProperties, "parameter 'uniqueProperties' is required");

        String propertyMessage = this.genPropertyMessage(dataObject, uniqueProperties);
        String errorMessage = StringResources.get("pisces-domain.UniquePropertyValidation.multiple.violation",
                propertyMessage);

        UniquePropertyObjectError uniquePropertyObjectError = new UniquePropertyObjectError(
                ObjectErrorCode.UNIQUE_MULTIPLE_VIOLATION, dataObject, null, errorMessage);
        uniquePropertyObjectError.validation = this;

        return uniquePropertyObjectError;
    }

    public List<String> getUniquePropertyNames() {
        return uniquePropertyNames;
    }

    public void setUniquePropertyNames(List<String> uniquePropertyNames) {
        this.uniquePropertyNames = uniquePropertyNames;
    }

    private String genPropertyMessage(Object dataObject, List<Property<?>> uniqueProperties) {
        StringBuilder errorMessage = new StringBuilder();

        for (Property<?> property : uniqueProperties) {
            IValueObject propertyValue = property.getValue(dataObject);
            if (propertyValue == null) {
                continue;
            }

            String msg = MessageFormat.format("{0}={1}", "\"" + property.toString() + "\"",
                    "\"" + propertyValue.getPresentValue() + "\"");

            errorMessage.append(msg);
            errorMessage.append(",");
        }

        int length = errorMessage.length();
        if (length > 0) {
            errorMessage.delete(length - 1, length);
        }

        return errorMessage.toString();
    }

    public static class UniquePropertyObjectError extends ObjectError
            implements IValidationObjectError<UniquePropertyValidation> {

        private UniquePropertyValidation validation;

        public UniquePropertyObjectError(String errorCode, Object object, String objectName, String errorMessage) {
            super(errorCode, object, objectName, errorMessage);
        }

        @Override
        public UniquePropertyValidation getValidation() {
            return validation;
        }

    }

}
